/**
 * {@link GSMDiscovererService} is responsible for scanning the gsm
 * network and gathering measurement so that the server can try to locate the
 * client.
 * 
 * @author SimpliX
 * 
 */
package ch.simplix.android.net.discoverer.gsm;

import java.util.concurrent.TimeUnit;

import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.telephony.CellLocation;
import android.telephony.NeighboringCellInfo;
import android.telephony.PhoneStateListener;
import android.telephony.ServiceState;
import android.telephony.SignalStrength;
import android.telephony.TelephonyManager;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import android.util.Log;
import ch.simplix.android.net.discoverer.bluetooth.BluetoothDiscovererService;
import ch.simplix.android.repetitive.service.implementation.ARepetitiveService;

/**
 * {@link GSMDiscovererService} is responsible for scanning the GSM network and
 * gathering measurement so that the server can try to locate the client.
 * @author Reto E. Koenig (reto.koenig@unifr.ch)
 * 
 */
public class GSMDiscovererService extends ARepetitiveService {

	/** Action being broadcasted whenever a new measurement was retrieved */
	public static String GSM_ACTION = "ch.simplix.android.net.discoverer.gsm.GSM_DISCOVERER_SERVICE";
	private static final String TAG = GSMDiscovererService.class
			.getSimpleName();
	private TelephonyManager telephonyManager;
	private PhoneStateListener phoneStateListener;
	private GSMMeasurement lastMeasurement;
	private GSMReading latestLocalCellReading;
	private String latestMCC;

	/**
	 * {@inheritDoc}
	 */
	@Override
	public void onCreate() {
		phoneStateListener = new MyPhoneStateListener();
		start();
		super.setUpdateInterval(30, TimeUnit.SECONDS);
	}		

	/**
	 * Retrieve measurement from last scan.
	 * 
	 * @return {@link Measurement}
	 */
	public GSMMeasurement getLatestMeasurement() {
		return lastMeasurement;
	}

	

	@Override
	public IBinder onBind(Intent intent) {
		return binder;
	}

	/**
	 * @see Binder
	 */
	public class LocalBinder extends Binder {
		public GSMDiscovererService getService() {
			return GSMDiscovererService.this;
		}
	}

	private final LocalBinder binder = new LocalBinder();

	
	
	@Override
	public void onStart(Intent intent){		
		start();
	}

	public void discover(){
		if (!super.isRunning()) {
			start();
			scan();
		}		
	}
	private void start() {
		if (telephonyManager != null)
			return;
		telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
		telephonyManager.listen(phoneStateListener,
				PhoneStateListener.LISTEN_SIGNAL_STRENGTHS
						| PhoneStateListener.LISTEN_SERVICE_STATE);
	}
	
	@Override
	public void onStop() {
		stop();
	}
	
	private void stop(){
		Log.d(TAG, "stopping");
		if (telephonyManager == null)
			return;
		telephonyManager.listen(phoneStateListener,
				PhoneStateListener.LISTEN_NONE);
		telephonyManager = null;
		Log.d(TAG, "stop");

	}

	private void scan() {		
		start();
		GSMMeasurement measurement = new GSMMeasurement();
		if(latestLocalCellReading!=null)
		{
			measurement.addGSMReading(latestLocalCellReading);
		}
		for (NeighboringCellInfo neighboringCellInfo : telephonyManager
				.getNeighboringCellInfo()) {
			GSMReading reading = new GSMReading();
			reading.setMCC(latestMCC);
			reading.setAreaId("" + neighboringCellInfo.getLac());
			reading.setCellId("" + neighboringCellInfo.getCid());
			reading.setSignalStrength(neighboringCellInfo.getRssi());
			reading.setNetworkType(neighboringCellInfo.getNetworkType());
			measurement.addGSMReading(reading);
		}
		lastMeasurement = measurement;

		Intent gsmIntent = new Intent(GSM_ACTION);
		sendBroadcast(gsmIntent);
		if(!super.isRunning()) stop();

	}

	private class MyPhoneStateListener extends PhoneStateListener {
		private ServiceState latestServiceState;

		/*
		 * Get the Signal strength from the provider, each time there is an
		 * update
		 */
		@Override
		public void onSignalStrengthsChanged(SignalStrength signalStrength) {
			super.onSignalStrengthsChanged(signalStrength);
			TelephonyManager tm=telephonyManager;
			if(tm==null) return;
			CellLocation cellLocation = tm.getCellLocation();
			if (cellLocation == null)
				return;
			if (cellLocation instanceof GsmCellLocation) {
				GsmCellLocation location = (GsmCellLocation) cellLocation;
				GSMReading reading = new GSMReading();
				reading.setMCC(latestMCC);
				reading.setAreaId("" + location.getLac());
				reading.setCellId("" + location.getCid());
				reading.setSignalStrength(signalStrength.getGsmSignalStrength());
				reading.setNetworkType(tm.getNetworkType());
				latestLocalCellReading = reading;
			} else if (cellLocation instanceof CdmaCellLocation) {
				CdmaCellLocation location = (CdmaCellLocation) cellLocation;
				GSMReading reading = new GSMReading();
				reading.setMCC(latestMCC);
				reading.setAreaId("CDMA: " + location.getNetworkId());
				reading.setCellId("CDMA: " + location.getBaseStationId());
				reading.setSignalStrength(signalStrength.getCdmaDbm());
				reading.setNetworkType(telephonyManager.getNetworkType());
				latestLocalCellReading = reading;
			}

			scan();
		}

		@Override
		public void onServiceStateChanged(ServiceState serviceState) {
			super.onServiceStateChanged(serviceState);
			this.latestServiceState = serviceState;
			String operatorNumeric = latestServiceState.getOperatorNumeric();
			if (operatorNumeric != null)
				latestMCC = operatorNumeric.substring(0, 3);
		}

	};/* End of private Class */

	@Override
	public void onRepeat() {
		scan();
	}
}